﻿#ifdef _WIN32

#include "completePort.h"

CallbackParser_IOCP callbackParser_IOCP = NULL;

static SOCKET g_server_socket;

static SOCKET g_Allsocket[SOCKETNUMBER];
static SELOVERLAPPED g_Alloverlap[SOCKETNUMBER];
static int g_count;

static HANDLE g_hComPort;
HANDLE *g_threadHead;

int g_threadNumber;

BOOL g_runFlag;


void InitComPort()
{
	g_runFlag = TRUE;

	//打开网络库
	WORD wVersionRequested = MAKEWORD(2, 2);
	WSADATA lpWSAData;
	int start_res = WSAStartup(wVersionRequested, &lpWSAData);
	if (start_res != 0)
	{
		return;
	}

	//校验版本
	if (HIBYTE(lpWSAData.wVersion) != 2 || LOBYTE(lpWSAData.wVersion) != 2)
	{
		WSACleanup();
		return;
	}

	//创建socket
	g_server_socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (INVALID_SOCKET == g_server_socket)
	{
		WSACleanup();
		return;
	}

	//绑定端口
	struct sockaddr_in ser_addrin;
	ser_addrin.sin_family = AF_INET;
	ser_addrin.sin_port = htons(32767);
	ser_addrin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int bind_res = bind(g_server_socket, (struct sockaddr*)&ser_addrin, sizeof(struct sockaddr));
	if (bind_res == SOCKET_ERROR)
	{
		WSACleanup();
		closesocket(g_server_socket);
		return;
	}

	g_Allsocket[g_count] = g_server_socket;
	g_Alloverlap[g_count].overlap.hEvent = WSACreateEvent();
	g_Alloverlap[g_count].buff = (char*)calloc(1, SOCKRECVSIZE);
	g_count++;
}

int createCompletePort()
{
	//创建完成端口
	g_hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
	if (g_hComPort == NULL)
	{
		WSACleanup();
		closesocket(g_server_socket);
		CloseHandle(g_Alloverlap[0].overlap.hEvent);
		g_count = 0;
		return -1;
	}

	//绑定完成端口
	HANDLE hPort = CreateIoCompletionPort((HANDLE)g_server_socket, g_hComPort, 0, 0);
	if (hPort != g_hComPort)
	{
		WSACleanup();
		closesocket(g_server_socket);
		CloseHandle(g_Alloverlap[0].overlap.hEvent);
		CloseHandle(g_hComPort);
		g_count = 0;
		return -1;
	}

	int lis_res = listen(g_server_socket, SOMAXCONN);
	if (SOCKET_ERROR == lis_res)
	{
		WSACleanup();
		closesocket(g_server_socket);
		CloseHandle(g_Alloverlap[0].overlap.hEvent);
		CloseHandle(g_hComPort);
		g_count = 0;
		return -1;
	}

	return 0;
}

int startThread()
{
	SYSTEM_INFO systemInfo;
	GetSystemInfo(&systemInfo);
	g_threadNumber = systemInfo.dwNumberOfProcessors;

	g_threadHead = (HANDLE*)malloc(sizeof(HANDLE) * g_threadNumber);

	for (int i = 0; i < g_threadNumber; i++)
	{
		g_threadHead[i] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
		if (g_threadHead[i] == NULL)
		{
			WSACleanup();
			closesocket(g_server_socket);
			CloseHandle(g_Alloverlap[0].overlap.hEvent);
			CloseHandle(g_hComPort);
			g_count = 0;
			return -1;
		}
	}

	PostAccept();//投递
	while (1);

	return 0;
}

void closeS()
{
	//关闭线程
	for (int i = 0; i < g_threadNumber; i++)
	{
		CloseHandle(g_threadHead[i]);
	}

	//关闭完成端口
	CloseHandle(g_hComPort);

	//关闭socket等数组
	for (int i = 0; i < g_count; i++)
	{
		if (g_Allsocket[i] != 0)
		{
			closesocket(g_Allsocket[i]);
		}
		if (g_Alloverlap[i].overlap.hEvent != NULL)
		{
			CloseHandle(g_Alloverlap[i].overlap.hEvent);
		}
		if (g_Alloverlap[i].buff != NULL)
		{
			free(g_Alloverlap[i].buff);
			g_Alloverlap[i].buff = NULL;
		}
	}

	WSACleanup();
}

DWORD WINAPI ThreadProc(LPVOID param)
{
	DWORD NumberOfBytesTransferred;
	ULONG_PTR lpCompletionKey = 0;
	LPOVERLAPPED lpOverlapped;

	while (g_runFlag)
	{
		//注意
		BOOL get_res = GetQueuedCompletionStatus(g_hComPort, &NumberOfBytesTransferred, &lpCompletionKey, &lpOverlapped, 1000);
		if (!get_res)
		{
			int a = GetLastError();
			if (a == ERROR_NETNAME_DELETED)//强制退出
			{
				return -1;
			}
			else if (a == WAIT_TIMEOUT)
			{
				continue;
			}
		}

		if (lpCompletionKey == 0)//accept
		{
			HANDLE hPort = CreateIoCompletionPort((HANDLE)g_Allsocket[g_count], g_hComPort, g_count, 0);
			if (hPort != g_hComPort)
			{
				closesocket(g_Allsocket[g_count]);
				CloseHandle(g_Alloverlap[g_count].overlap.hEvent);
				continue;
			}

			PostRecv(g_count);
			g_count++;
			PostAccept();
		}
		else//非服务器
		{
			if (NumberOfBytesTransferred == 0)//下线
			{
				printf("close\n");
				closesocket(g_Allsocket[lpCompletionKey]);
				CloseHandle(g_Alloverlap[lpCompletionKey].overlap.hEvent);

				g_Allsocket[lpCompletionKey] = 0;
				g_Alloverlap[lpCompletionKey].overlap.hEvent = NULL;
				free(g_Alloverlap[lpCompletionKey].buff);
				g_Alloverlap[lpCompletionKey].buff = NULL;
				continue;
			}
			else
			{
				SELOVERLAPPED* selovlap = (SELOVERLAPPED*)lpOverlapped;

				if (selovlap->flag == 1)//接收
				{
					if (callbackParser_IOCP != NULL)
					{
						callbackParser_IOCP(selovlap->buff, g_Alloverlap[lpCompletionKey].buff);
					}
					g_Alloverlap[lpCompletionKey].flag = 0;
					PostSend(lpCompletionKey);
				}
				else//发送
				{
					g_Alloverlap[lpCompletionKey].flag = 0;
					PostRecv(lpCompletionKey);
				}
				memset(selovlap->buff, 0, SOCKRECVSIZE);
			}
		}
	}

	return 0;
}

int PostAccept()
{
	//创建socket
	g_Allsocket[g_count] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	g_Alloverlap[g_count].overlap.hEvent = WSACreateEvent();
	g_Alloverlap[g_count].buff = (char*)calloc(1, SOCKRECVSIZE);
	if (INVALID_SOCKET == g_Allsocket[g_count])
	{
		WSACleanup();
		return -1;
	}

	//接收
	DWORD receiveOne = 0;
	BOOL resacc = AcceptEx(g_server_socket, g_Allsocket[g_count], g_Alloverlap[0].buff, 0, 
		sizeof(struct sockaddr) + 16, sizeof(struct sockaddr) + 16, &receiveOne, (OVERLAPPED*)&g_Alloverlap[0]);
	if (!resacc)
	{
		int a = GetLastError();
		if (a == ERROR_IO_PENDING)//阻塞等待
		{
			return 1;
		}
		else
		{
			return -1;//出现错误
		}
	}
	return 0;//立即收到链接
}

int PostRecv(int index)
{
	WSABUF wsabuf;
	wsabuf.buf = g_Alloverlap[index].buff;
	wsabuf.len = SOCKRECVSIZE;

	DWORD flag = 0;
	DWORD recvflag = 0;

	g_Alloverlap[index].flag = 1;

	int res_recv = WSARecv(g_Allsocket[index], &wsabuf, 1, &recvflag ,&flag, (OVERLAPPED*)&g_Alloverlap[index], NULL);
	if (!res_recv)
	{
		int a = GetLastError();
		if (a == ERROR_IO_PENDING)//阻塞等待
		{
			return 1;
		}
		else
		{
			return -1;//出现错误
		}
	}
	return 0;//立即收到链接
}

int PostSend(int index)
{
	WSABUF wsabuf;
	wsabuf.buf = g_Alloverlap[index].buff;
	wsabuf.len = SOCKRECVSIZE;

	DWORD recvflag = 0;
	DWORD flag = 0;

	g_Alloverlap[index].flag = 2;

	int res_send = WSASend(g_Allsocket[index], &wsabuf, 1, &recvflag, flag, (OVERLAPPED*)&g_Alloverlap[index], NULL);
	if (!res_send)
	{
		int a = GetLastError();
		if (a == ERROR_IO_PENDING)//阻塞等待
		{
			return 1;
		}
		else
		{
			return -1;//出现错误
		}
	}
	return 0;//立即收到链接
}

void SetCallbackFun_IOCP(CallbackParser_IOCP callback_IOCP)
{
	callbackParser_IOCP = callback_IOCP;
}

#endif
